package cn.lysj.framework.common.validate.reflect;

import cn.lysj.framework.common.validate.entity.Entity;
import cn.lysj.framework.common.validate.exception.ValidatorException;
import cn.lysj.framework.common.validate.helper.AnnotationHelper;
import cn.lysj.framework.common.validate.param.Param;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author ww
 * @date 2018-08-22 10:18
 * @Description 反射工具
 */
public class ReflectUtils {

    /**
     * explain: 获取校验对象内属性的所有校验注解放入
     * @param object 待校验的对象
     * @param map 忽略某个参数上的注解的校验
     * @throws  IllegalAccessException 当获取field值获取不到时，抛出该异常
     **/
    public static Set<Entity> getSet(Object object, Map<String,Set<Class<? extends Annotation>>> map) throws IllegalAccessException {
        Set<Entity> set = new LinkedHashSet<>();
        Class clazz = object.getClass(); //获取类的类型（类型类）
        Field[] fields = clazz.getDeclaredFields();//获取所有类中的参数
        for (Field field : fields) {
            Set<Annotation> list = new LinkedHashSet<>();
            field.setAccessible(true);//类中的成员变量为private,故必须进行此操作
            if(map.isEmpty()){
                AnnotationHelper.choice(field,list);//获取参数上注解的类
            }else{
                AnnotationHelper.choice(field,list,map);//获取参数上注解的类
            }
            if (list.size() == 0) continue; //如果集合中没有存放自定义的注解则跳过
            for (Annotation annotation1 : list){
//                System.err.println(annotation1.toString()+":"+annotation1.toString().contains(Param.NOT));
                if(annotation1.toString().contains(Param.NOT)){
                    set.add(new Entity(annotation1, field, field.get(object),true,clazz));//field.get(object)  获取这个参数中的值
                }else{
                    set.add(new Entity(annotation1, field, field.get(object),false,clazz));//field.get(object)  获取这个参数中的值
                }
            }
        }
        return set;
    }

    /**
     * explain: 获取Object[]内的参数类型 {entity}
     * @param args invokeMethod 方法的参数值
     **/
    private static Class<?>[] getType(Object ...args) {
        if (null == args) {
            return new Class<?>[]{};
        }
        Class<?>[] classType = new Class<?>[args.length];
        for (int i = 0; i < args.length; i++) {
            classType[i] = args[i].getClass();
        }
        return classType;
    }

    /**
     * explain: 反射执行方法
     * @param clazz 待执行的class   校验类的class    class org.yxs.medusa.validate.NullValidate
     * @param args 方法参数        {entity}  多个的情况可以用数组替代
     * @param methodName 方法名    result
     * @throws  ValidatorException
     **/
    public static Object invokeMethod(Class<?> clazz, String methodName, Object ...args) {
        try {
            //public org.yxs.medusa.Medusa org.yxs.medusa.validate.AbstractValidate.result(org.yxs.medusa.Entity)
            Method method = clazz.getMethod(methodName, getType(args)); //获取result方法
            return method.invoke(clazz.newInstance(), args); //执行result方法
        } catch (Exception e) {
            throw new ValidatorException(e);
        }
    }
}
